using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Transactions;
using IsolationLevel = System.Data.IsolationLevel;

namespace Dapper.Extensions.Hooks
{
    internal class WrappedConnection<T>(DbConnection connection, ISqlHooks<T> hooks, T context) : DbConnection
    {
	    public override void Close()
        {
            var sw = Stopwatch.StartNew();
            try
            {
                connection.Close();
            }
            finally
            {
                hooks.ConnectionClosed(this, context, sw.ElapsedMilliseconds);
            }
        }

        public override void Open()
        {
            var sw = Stopwatch.StartNew();
            try
            {
                connection.Open();
            }
            finally
            {
                hooks.ConnectionOpened(this, context, sw.ElapsedMilliseconds);
            }
        }

        public override async Task OpenAsync(CancellationToken cancellationToken)
        {
            var sw = Stopwatch.StartNew();
            try
            {
                await connection.OpenAsync(cancellationToken);
            }
            finally
            {
                hooks.ConnectionOpened(this, context, sw.ElapsedMilliseconds);
            }
        }

        protected override DbCommand CreateDbCommand() => 
            new WrappedCommand<T>(connection.CreateCommand(), this, hooks, context);

        //other members

        public override string ConnectionString
        {
            get => connection.ConnectionString;
            set => connection.ConnectionString = value;
        }

        public override int ConnectionTimeout => connection.ConnectionTimeout;
        public override string Database => connection.Database;
        public override string DataSource => connection.DataSource;
        public override string ServerVersion => connection.ServerVersion;
        public override ConnectionState State => connection.State;
        public override void ChangeDatabase(string databaseName) => connection.ChangeDatabase(databaseName);
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => connection.BeginTransaction(isolationLevel);
        protected override bool CanRaiseEvents => false;
        public override void EnlistTransaction(Transaction? transaction) => connection.EnlistTransaction(transaction);
        public override DataTable GetSchema() => connection.GetSchema();
        public override DataTable GetSchema(string collectionName) => connection.GetSchema(collectionName);
        public override DataTable GetSchema(string collectionName, string?[] restrictionValues) => connection.GetSchema(collectionName, restrictionValues);

        protected override void Dispose(bool disposing)
        {
            if (disposing)
                connection.Dispose();

            base.Dispose(disposing);
        }
    }
}
